<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <base data-ice="baseUrl" href="../../../../../">
  <title data-ice="title">src/plugins/lib/ui/index.js | xeokit-sdk</title>
  <link type="text/css" rel="stylesheet" href="css/style.css">
  <link type="text/css" rel="stylesheet" href="css/prettify-tomorrow.css">
  <script src="script/prettify/prettify.js"></script>
  <script src="script/manual.js"></script>
<meta name="description" content="3D engineering graphics in the browser"><meta property="og:type" content="website"><meta property="og:url" content="http://xeokit.io"><meta property="og:site_name" content="xeokit-sdk"><meta property="og:title" content="xeokit-sdk"><meta property="og:image" content="./images/logo.jpg"><meta property="og:description" content="3D engineering graphics in the browser"><meta property="og:author" content="http://xeolabs.com"><meta property="twitter:card" content="summary"><meta property="twitter:title" content="xeokit-sdk"><meta property="twitter:description" content="3D engineering graphics in the browser"><meta property="twitter:image" content="./images/logo.jpg"></head>
<body class="layout-container" data-ice="rootContainer">

<header>
  <a href="./" style="display: flex; align-items: center;"><img src="./image/brand_logo.jpg" style="width:34px;"></a>
  
  <a href="identifiers.html">Reference</a>
  <a href="source.html">Source</a>
  
  <div class="search-box">
  <span>
    <img src="./image/search.png">
    <span class="search-input-edge"></span><input class="search-input"><span class="search-input-edge"></span>
  </span>
    <ul class="search-result"></ul>
  </div>
<a style="position:relative; top:3px;" href="https://github.com/xeokit/xeokit-sdk"><img width="20px" src="./image/github.png"></a></header>

<nav class="navigation" data-ice="nav"><div>
  <ul>
    
  <li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-contextmenu">extras/ContextMenu</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extras/ContextMenu/ContextMenu.js~ContextMenu.html">ContextMenu</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-marqueepicker">extras/MarqueePicker</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extras/MarqueePicker/MarqueePicker.js~MarqueePicker.html">MarqueePicker</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extras/MarqueePicker/MarqueePickerMouseControl.js~MarqueePickerMouseControl.html">MarqueePickerMouseControl</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-pointercircle">extras/PointerCircle</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extras/PointerCircle/PointerCircle.js~PointerCircle.html">PointerCircle</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-pointerlens">extras/PointerLens</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extras/PointerLens/PointerLens.js~PointerLens.html">PointerLens</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-skybox">extras/Skybox</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createCombinedTexture">createCombinedTexture</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createSkyboxMesh">createSkyboxMesh</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-spheremap">extras/SphereMap</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-createSphereMapMesh">createSphereMapMesh</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#extras-collision">extras/collision</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/extras/collision/ObjectsKdTree3.js~ObjectsKdTree3.html">ObjectsKdTree3</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-anglemeasurementsplugin">plugins/AngleMeasurementsPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/AngleMeasurement.js~AngleMeasurement.html">AngleMeasurement</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsMouseControl.js~AngleMeasurementsMouseControl.html">AngleMeasurementsMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsPlugin.js~AngleMeasurementsPlugin.html">AngleMeasurementsPlugin</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsTouchControl.js~AngleMeasurementsTouchControl.html">AngleMeasurementsTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/index.js~AngleMeasurementEditControl.html">AngleMeasurementEditControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/index.js~AngleMeasurementEditMouseControl.html">AngleMeasurementEditMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/index.js~AngleMeasurementEditTouchControl.html">AngleMeasurementEditTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-interface">I</span><span data-ice="name"><span><a href="class/src/plugins/AngleMeasurementsPlugin/AngleMeasurementsControl.js~AngleMeasurementsControl.html">AngleMeasurementsControl</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-annotationsplugin">plugins/AnnotationsPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AnnotationsPlugin/Annotation.js~Annotation.html">Annotation</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AnnotationsPlugin/AnnotationsPlugin.js~AnnotationsPlugin.html">AnnotationsPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-axisgizmoplugin">plugins/AxisGizmoPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/AxisGizmoPlugin/AxisGizmoPlugin.js~AxisGizmoPlugin.html">AxisGizmoPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-bcfviewpointsplugin">plugins/BCFViewpointsPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/BCFViewpointsPlugin/BCFViewpointsPlugin.js~BCFViewpointsPlugin.html">BCFViewpointsPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-cityjsonloaderplugin">plugins/CityJSONLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/CityJSONLoaderPlugin/CityJSONDefaultDataSource.js~CityJSONDefaultDataSource.html">CityJSONDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/CityJSONLoaderPlugin/CityJSONLoaderPlugin.js~CityJSONLoaderPlugin.html">CityJSONLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-cxconverterifcloaderplugin">plugins/CxConverterIFCLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/CxConverterIFCLoaderPlugin/CxConverterIFCLoaderPlugin.js~CxConverterIFCLoaderPlugin.html">CxConverterIFCLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-distancemeasurementsplugin">plugins/DistanceMeasurementsPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurement.js~DistanceMeasurement.html">DistanceMeasurement</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsMouseControl.js~DistanceMeasurementsMouseControl.html">DistanceMeasurementsMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsPlugin.js~DistanceMeasurementsPlugin.html">DistanceMeasurementsPlugin</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsTouchControl.js~DistanceMeasurementsTouchControl.html">DistanceMeasurementsTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/index.js~DistanceMeasurementEditControl.html">DistanceMeasurementEditControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/index.js~DistanceMeasurementEditMouseControl.html">DistanceMeasurementEditMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/index.js~DistanceMeasurementEditTouchControl.html">DistanceMeasurementEditTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-interface">I</span><span data-ice="name"><span><a href="class/src/plugins/DistanceMeasurementsPlugin/DistanceMeasurementsControl.js~DistanceMeasurementsControl.html">DistanceMeasurementsControl</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-dotbimloaderplugin">plugins/DotBIMLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DotBIMLoaderPlugin/DotBIMDefaultDataSource.js~DotBIMDefaultDataSource.html">DotBIMDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/DotBIMLoaderPlugin/DotBIMLoaderPlugin.js~DotBIMLoaderPlugin.html">DotBIMLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-facealignedsectionplanesplugin">plugins/FaceAlignedSectionPlanesPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/FaceAlignedSectionPlanesPlugin/FaceAlignedSectionPlanesControl.js~FaceAlignedSectionPlanesControl.html">FaceAlignedSectionPlanesControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/FaceAlignedSectionPlanesPlugin/FaceAlignedSectionPlanesPlugin.js~FaceAlignedSectionPlanesPlugin.html">FaceAlignedSectionPlanesPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-fastnavplugin">plugins/FastNavPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/FastNavPlugin/FastNavPlugin.js~FastNavPlugin.html">FastNavPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-gltfloaderplugin">plugins/GLTFLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/GLTFLoaderPlugin/GLTFDefaultDataSource.js~GLTFDefaultDataSource.html">GLTFDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/GLTFLoaderPlugin/GLTFLoaderPlugin.js~GLTFLoaderPlugin.html">GLTFLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-lasloaderplugin">plugins/LASLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/LASLoaderPlugin/LASDefaultDataSource.js~LASDefaultDataSource.html">LASDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/LASLoaderPlugin/LASLoaderPlugin.js~LASLoaderPlugin.html">LASLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-navcubeplugin">plugins/NavCubePlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/NavCubePlugin/NavCubePlugin.js~NavCubePlugin.html">NavCubePlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-objloaderplugin">plugins/OBJLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/OBJLoaderPlugin/OBJLoaderPlugin.js~OBJLoaderPlugin.html">OBJLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-stlloaderplugin">plugins/STLLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/STLLoaderPlugin/STLDefaultDataSource.js~STLDefaultDataSource.html">STLDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/STLLoaderPlugin/STLLoaderPlugin.js~STLLoaderPlugin.html">STLLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-sectionplanesplugin">plugins/SectionPlanesPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/SectionPlanesPlugin/SectionPlanesPlugin.js~SectionPlanesPlugin.html">SectionPlanesPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-storeyviewsplugin">plugins/StoreyViewsPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/StoreyViewsPlugin/Storey.js~Storey.html">Storey</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/StoreyViewsPlugin/StoreyMap.js~StoreyMap.html">StoreyMap</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/StoreyViewsPlugin/StoreyViewsPlugin.js~StoreyViewsPlugin.html">StoreyViewsPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-treeviewplugin">plugins/TreeViewPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/TreeViewPlugin/RenderService.js~RenderService.html">RenderService</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-interface">I</span><span data-ice="name"><span><a href="class/src/plugins/TreeViewPlugin/TreeViewNode.js~TreeViewNode.html">TreeViewNode</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-viewcullplugin">plugins/ViewCullPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ViewCullPlugin/ViewCullPlugin.js~ViewCullPlugin.html">ViewCullPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-webifcloaderplugin">plugins/WebIFCLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/WebIFCLoaderPlugin/WebIFCDefaultDataSource.js~WebIFCDefaultDataSource.html">WebIFCDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/WebIFCLoaderPlugin/WebIFCLoaderPlugin.js~WebIFCLoaderPlugin.html">WebIFCLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-xktloaderplugin">plugins/XKTLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/XKTLoaderPlugin/XKTDefaultDataSource.js~XKTDefaultDataSource.html">XKTDefaultDataSource</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/XKTLoaderPlugin/XKTLoaderPlugin.js~XKTLoaderPlugin.html">XKTLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-xml3dloaderplugin">plugins/XML3DLoaderPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/XML3DLoaderPlugin/XML3DLoaderPlugin.js~XML3DLoaderPlugin.html">XML3DLoaderPlugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-zonesplugin">plugins/ZonesPlugin</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZoneEditControl.html">ZoneEditControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZoneEditMouseControl.html">ZoneEditMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZoneEditTouchControl.html">ZoneEditTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZoneTranslateControl.html">ZoneTranslateControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZoneTranslateMouseControl.html">ZoneTranslateMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZoneTranslateTouchControl.html">ZoneTranslateTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZonesAAZoneControl.html">ZonesAAZoneControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZonesMouseControl.html">ZonesMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZonesPlugin.html">ZonesPlugin</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZonesPolysurfaceMouseControl.html">ZonesPolysurfaceMouseControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZonesPolysurfaceTouchControl.html">ZonesPolysurfaceTouchControl</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/ZonesPlugin/ZonesPlugin.js~ZonesTouchControl.html">ZonesTouchControl</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-lib-html">plugins/lib/html</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-addContextMenuListener">addContextMenuListener</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#plugins-lib-ui">plugins/lib/ui</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/lib/ui/index.js~Dot3D.html">Dot3D</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/lib/ui/index.js~Label3D.html">Label3D</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/plugins/lib/ui/index.js~Wire3D.html">Wire3D</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-activateDraggableDot">activateDraggableDot</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-activateDraggableDots">activateDraggableDots</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-addMousePressListener">addMousePressListener</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-addTouchPressListener">addTouchPressListener</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-marker3D">marker3D</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-startPolygonCreate">startPolygonCreate</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-touchPointSelector">touchPointSelector</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-transformToNode">transformToNode</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-triangulateEarClipping">triangulateEarClipping</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-wire3D">wire3D</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer">viewer</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/Configs.js~Configs.html">Configs</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/Plugin.js~Plugin.html">Plugin</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-localization">viewer/localization</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/localization/LocaleService.js~LocaleService.html">LocaleService</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-metadata">viewer/metadata</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/metadata/MetaModel.js~MetaModel.html">MetaModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/metadata/MetaObject.js~MetaObject.html">MetaObject</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/metadata/MetaScene.js~MetaScene.html">MetaScene</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/metadata/Property.js~Property.html">Property</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/metadata/PropertySet.js~PropertySet.html">PropertySet</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-IFCObjectDefaultColors">IFCObjectDefaultColors</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-IFCObjectDefaults">IFCObjectDefaults</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene">viewer/scene</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/Component.js~Component.html">Component</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-interface">I</span><span data-ice="name"><span><a href="class/src/viewer/scene/Entity.js~Entity.html">Entity</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-stats">stats</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-bitmap">viewer/scene/Bitmap</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/Bitmap/Bitmap.js~Bitmap.html">Bitmap</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-imageplane">viewer/scene/ImagePlane</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/ImagePlane/ImagePlane.js~ImagePlane.html">ImagePlane</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-lineset">viewer/scene/LineSet</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/LineSet/LineSet.js~LineSet.html">LineSet</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-camera">viewer/scene/camera</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/Camera.js~Camera.html">Camera</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/CameraFlightAnimation.js~CameraFlightAnimation.html">CameraFlightAnimation</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/CameraPath.js~CameraPath.html">CameraPath</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/CameraPathAnimation.js~CameraPathAnimation.html">CameraPathAnimation</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/CustomProjection.js~CustomProjection.html">CustomProjection</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/Frustum.js~Frustum.html">Frustum</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/Ortho.js~Ortho.html">Ortho</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/camera/Perspective.js~Perspective.html">Perspective</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-canvas">viewer/scene/canvas</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/canvas/Canvas.js~Canvas.html">Canvas</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/canvas/Spinner.js~Spinner.html">Spinner</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-constants">viewer/scene/constants</a><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-AlphaFormat">AlphaFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-ByteType">ByteType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-ClampToEdgeWrapping">ClampToEdgeWrapping</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-CompressedMediaType">CompressedMediaType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-DepthFormat">DepthFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-DepthStencilFormat">DepthStencilFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-FloatType">FloatType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-GIFMediaType">GIFMediaType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-HalfFloatType">HalfFloatType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-IntType">IntType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-JPEGMediaType">JPEGMediaType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LinearEncoding">LinearEncoding</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LinearFilter">LinearFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LinearMipMapLinearFilter">LinearMipMapLinearFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LinearMipMapNearestFilter">LinearMipMapNearestFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LinearMipmapLinearFilter">LinearMipmapLinearFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LinearMipmapNearestFilter">LinearMipmapNearestFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LuminanceAlphaFormat">LuminanceAlphaFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-LuminanceFormat">LuminanceFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-MirroredRepeatWrapping">MirroredRepeatWrapping</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NearestFilter">NearestFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NearestMipMapLinearFilter">NearestMipMapLinearFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NearestMipMapNearestFilter">NearestMipMapNearestFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NearestMipmapLinearFilter">NearestMipmapLinearFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-NearestMipmapNearestFilter">NearestMipmapNearestFilter</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-PNGMediaType">PNGMediaType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBAFormat">RGBAFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBAIntegerFormat">RGBAIntegerFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_10x10_Format">RGBA_ASTC_10x10_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_10x5_Format">RGBA_ASTC_10x5_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_10x6_Format">RGBA_ASTC_10x6_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_10x8_Format">RGBA_ASTC_10x8_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_12x10_Format">RGBA_ASTC_12x10_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_12x12_Format">RGBA_ASTC_12x12_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_4x4_Format">RGBA_ASTC_4x4_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_5x4_Format">RGBA_ASTC_5x4_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_5x5_Format">RGBA_ASTC_5x5_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_6x5_Format">RGBA_ASTC_6x5_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_6x6_Format">RGBA_ASTC_6x6_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_8x5_Format">RGBA_ASTC_8x5_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_8x6_Format">RGBA_ASTC_8x6_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ASTC_8x8_Format">RGBA_ASTC_8x8_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_BPTC_Format">RGBA_BPTC_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_ETC2_EAC_Format">RGBA_ETC2_EAC_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_PVRTC_2BPPV1_Format">RGBA_PVRTC_2BPPV1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_PVRTC_4BPPV1_Format">RGBA_PVRTC_4BPPV1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_S3TC_DXT1_Format">RGBA_S3TC_DXT1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_S3TC_DXT3_Format">RGBA_S3TC_DXT3_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBA_S3TC_DXT5_Format">RGBA_S3TC_DXT5_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGBFormat">RGBFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGB_ETC1_Format">RGB_ETC1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGB_ETC2_Format">RGB_ETC2_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGB_PVRTC_2BPPV1_Format">RGB_PVRTC_2BPPV1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGB_PVRTC_4BPPV1_Format">RGB_PVRTC_4BPPV1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGB_S3TC_DXT1_Format">RGB_S3TC_DXT1_Format</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGFormat">RGFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RGIntegerFormat">RGIntegerFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RedFormat">RedFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RedIntegerFormat">RedIntegerFormat</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-RepeatWrapping">RepeatWrapping</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-ShortType">ShortType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UnsignedByteType">UnsignedByteType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UnsignedInt248Type">UnsignedInt248Type</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UnsignedIntType">UnsignedIntType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UnsignedShort4444Type">UnsignedShort4444Type</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UnsignedShort5551Type">UnsignedShort5551Type</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-UnsignedShortType">UnsignedShortType</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-sRGBEncoding">sRGBEncoding</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-geometry">viewer/scene/geometry</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/geometry/Geometry.js~Geometry.html">Geometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/geometry/ReadableGeometry.js~ReadableGeometry.html">ReadableGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/geometry/VBOGeometry.js~VBOGeometry.html">VBOGeometry</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-geometry-builders">viewer/scene/geometry/builders</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildBoxGeometry">buildBoxGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildBoxLinesGeometry">buildBoxLinesGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildBoxLinesGeometryFromAABB">buildBoxLinesGeometryFromAABB</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildCylinderGeometry">buildCylinderGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildGridGeometry">buildGridGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildLineGeometry">buildLineGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildPlaneGeometry">buildPlaneGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildPolylineGeometry">buildPolylineGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildPolylineGeometryFromCurve">buildPolylineGeometryFromCurve</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildSphereGeometry">buildSphereGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildTorusGeometry">buildTorusGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-buildVectorTextGeometry">buildVectorTextGeometry</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-geometry-loaders">viewer/scene/geometry/loaders</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-load3DSGeometry">load3DSGeometry</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-loadOBJGeometry">loadOBJGeometry</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-input">viewer/scene/input</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/input/Input.js~Input.html">Input</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-libs">viewer/scene/libs</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-deviation">deviation</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-earcut">earcut</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-flatten">flatten</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-lights">viewer/scene/lights</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/AmbientLight.js~AmbientLight.html">AmbientLight</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/CubeTexture.js~CubeTexture.html">CubeTexture</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/DirLight.js~DirLight.html">DirLight</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/Light.js~Light.html">Light</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/LightMap.js~LightMap.html">LightMap</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/PointLight.js~PointLight.html">PointLight</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/ReflectionMap.js~ReflectionMap.html">ReflectionMap</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/lights/Shadow.js~Shadow.html">Shadow</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-marker">viewer/scene/marker</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/marker/Marker.js~Marker.html">Marker</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/marker/SpriteMarker.js~SpriteMarker.html">SpriteMarker</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-materials">viewer/scene/materials</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/EdgeMaterial.js~EdgeMaterial.html">EdgeMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/EmphasisMaterial.js~EmphasisMaterial.html">EmphasisMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/Fresnel.js~Fresnel.html">Fresnel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/LambertMaterial.js~LambertMaterial.html">LambertMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/LinesMaterial.js~LinesMaterial.html">LinesMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/Material.js~Material.html">Material</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/MetallicMaterial.js~MetallicMaterial.html">MetallicMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/PhongMaterial.js~PhongMaterial.html">PhongMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/PointsMaterial.js~PointsMaterial.html">PointsMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/SpecularMaterial.js~SpecularMaterial.html">SpecularMaterial</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/materials/Texture.js~Texture.html">Texture</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-math">viewer/scene/math</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/math/MeshSurfaceArea.js~MeshSurfaceArea.html">MeshSurfaceArea</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/math/MeshVolume.js~MeshVolume.html">MeshVolume</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-meshSurfaceArea">meshSurfaceArea</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-meshVolume">meshVolume</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-mementos">viewer/scene/mementos</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/mementos/CameraMemento.js~CameraMemento.html">CameraMemento</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/mementos/ModelMemento.js~ModelMemento.html">ModelMemento</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/mementos/ObjectsMemento.js~ObjectsMemento.html">ObjectsMemento</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-mesh">viewer/scene/mesh</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/mesh/Mesh.js~Mesh.html">Mesh</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-mesh-draw">viewer/scene/mesh/draw</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-DrawShaderSource">DrawShaderSource</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-metriqs">viewer/scene/metriqs</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/metriqs/Metriqs.js~Metrics.html">Metrics</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-model">viewer/scene/model</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/PerformanceModel.js~PerformanceModel.html">PerformanceModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/SceneModel.js~SceneModel.html">SceneModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/SceneModelEntity.js~SceneModelEntity.html">SceneModelEntity</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/SceneModelMesh.js~SceneModelMesh.html">SceneModelMesh</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/SceneModelTexture.js~SceneModelTexture.html">SceneModelTexture</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/SceneModelTextureSet.js~SceneModelTextureSet.html">SceneModelTextureSet</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/SceneModelTransform.js~SceneModelTransform.html">SceneModelTransform</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/model/VBOSceneModel.js~VBOSceneModel.html">VBOSceneModel</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-uniquifyPositions">uniquifyPositions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-rebucketPositions">rebucketPositions</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-model-dtx-lines">viewer/scene/model/dtx/lines</a><span data-ice="kind" class="kind-function">F</span><span data-ice="name"><span><a href="function/index.html#static-function-rebucketPositions">rebucketPositions</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-dataTextureRamStats">dataTextureRamStats</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-model-dtx-triangles-lib">viewer/scene/model/dtx/triangles/lib</a><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-dataTextureRamStats">dataTextureRamStats</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-nodes">viewer/scene/nodes</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/nodes/Node.js~Node.html">Node</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-paths">viewer/scene/paths</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/paths/CubicBezierCurve.js~CubicBezierCurve.html">CubicBezierCurve</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/paths/Curve.js~Curve.html">Curve</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/paths/Path.js~Path.html">Path</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/paths/QuadraticBezierCurve.js~QuadraticBezierCurve.html">QuadraticBezierCurve</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/paths/SplineCurve.js~SplineCurve.html">SplineCurve</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-postfx">viewer/scene/postfx</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/postfx/CrossSections.js~CrossSections.html">CrossSections</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/postfx/SAO.js~SAO.html">SAO</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-scene">viewer/scene/scene</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/scene/Scene.js~Scene.html">Scene</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-sectioncaps">viewer/scene/sectionCaps</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/sectionCaps/SectionCaps.js~SectionCaps.html">SectionCaps</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-sectionplane">viewer/scene/sectionPlane</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/sectionPlane/SectionPlane.js~SectionPlane.html">SectionPlane</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/sectionPlane/SectionPlaneCache.js~SectionPlaneCache.html">SectionPlaneCache</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-utils">viewer/scene/utils</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/utils/FileLoader.js~FileLoader.html">FileLoader</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/utils/Loader.js~Loader.html">Loader</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/utils/LoadingManager.js~LoadingManager.html">LoadingManager</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/utils/WorkerPool.js~WorkerPool.html">WorkerPool</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-Cache">Cache</a></span></span></li>
<li data-ice="doc"><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-DefaultLoadingManager">DefaultLoadingManager</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-utils-texturetranscoders">viewer/scene/utils/textureTranscoders</a><span data-ice="kind" class="kind-interface">I</span><span data-ice="name"><span><a href="class/src/viewer/scene/utils/textureTranscoders/TextureTranscoder.js~TextureTranscoder.html">TextureTranscoder</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-utils-texturetranscoders-ktx2texturetranscoder">viewer/scene/utils/textureTranscoders/KTX2TextureTranscoder</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/utils/textureTranscoders/KTX2TextureTranscoder/KTX2TextureTranscoder.js~KTX2TextureTranscoder.html">KTX2TextureTranscoder</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-viewport">viewer/scene/viewport</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/viewport/Viewport.js~Viewport.html">Viewport</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-scene-webgl">viewer/scene/webgl</a><span data-ice="kind" class="kind-class">C</span><span data-ice="name"><span><a href="class/src/viewer/scene/webgl/PickResult.js~PickResult.html">PickResult</a></span></span></li>
<li data-ice="doc"><a data-ice="dirPath" class="nav-dir-path" href="identifiers.html#viewer-utils">viewer/utils</a><span data-ice="kind" class="kind-variable">V</span><span data-ice="name"><span><a href="variable/index.html#static-variable-os">os</a></span></span></li>
</ul>
</div>
</nav>

<div class="content" data-ice="content"><h1 data-ice="title">src/plugins/lib/ui/index.js</h1>
<pre class="source-code line-number raw-source-code"><code class="prettyprint linenums" data-ice="content">import {Dot} from &quot;../html/Dot.js&quot;;
import {Label} from &quot;../html/Label.js&quot;;
import {Wire} from &quot;../html/Wire.js&quot;;
import {math} from &quot;../../../viewer/scene/math/math.js&quot;;
import {Marker} from &quot;../../../viewer/scene/marker/Marker.js&quot;;

const tmpVec2a = math.vec2();
const tmpVec2b = math.vec2();
const tmpVec2c = math.vec2();
const tmpVec2d = math.vec2();
const tmpVec3a = math.vec3();
const tmpVec3b = math.vec3();
const tmpVec4a = math.vec4();
const tmpVec4b = math.vec4();
const tmpVec4c = math.vec4();
const tmpVec4d = math.vec4();
const tmpMat4  = math.mat4();
const tmpRay = {
    origin:    math.vec3(),
    direction: math.vec3()
};

const nop = () =&gt; { };

const planeIntersect = function(p0, n, origin, direction) {
    const t = (p0 - math.dotVec3(origin, n)) / math.dotVec3(direction, n);
    if (t &lt; 0)
    {
        return null;
    }
    else
    {
        const worldPos = math.vec3();
        math.mulVec3Scalar(direction, t, worldPos);
        math.addVec3(origin, worldPos, worldPos);
        return worldPos;
    }
};

export function transformToNode(from, to, vec) {
    const fromRec = from.getBoundingClientRect();
    const toRec = to.getBoundingClientRect();
    vec[0] += fromRec.left - toRec.left;
    vec[1] += fromRec.top  - toRec.top;
};

const toClipSpace = (camera, worldPos, p) =&gt; {
    // The reason the projMatrix is explicitely fetched as below is a complex callback chain
    // leading from a boundary update to a viewMatrix and projMatrix updates, which change their values
    // in the mid of the toClipSpace, leading to incorrect values.
    // The fetch ensures that matrix values are stabilized before used to transform worldPos to p.
    // Better solution would be to ensure that no mutually-triggered callbacks
    // (like boundary =&gt; view/projMatrix in this situation) ever happen, so user code can rely
    // on a callback running in a stable context.
    tmpMat4.set(camera.viewMatrix);
    tmpMat4.set(camera.projMatrix);
    // to homogeneous coords
    p.set(worldPos);
    p[3] = 1;

    // to clip space
    math.mulMat4v4(camera.viewMatrix, p, p);
    math.mulMat4v4(camera.projMatrix, p, p);
};

const toCanvasSpace = (canvas, parentElement, ndc, p) =&gt; {
    p[0] = (1 + ndc[0]) * 0.5 * canvas.offsetWidth;
    p[1] = (1 - ndc[1]) * 0.5 * canvas.offsetHeight;
    transformToNode(canvas, parentElement, p);
};

const clipSegment = (scene, parentElement, start, end, canvasStart, canvasEnd) =&gt; {
    const camera = scene.camera;
    const canvas = scene.canvas.canvas;

    if (math.distVec3(start, end) &lt; 0.001) {
        return false;
    }

    const delta = math.subVec3(end, start, tmpVec3a);
    let s_min = 0.0;
    let s_max = 1.0;

    for (let plane of scene._sectionPlanesState.sectionPlanes) {
        const endDot   = math.dotVec3(plane.dir, math.subVec3(plane.pos, end,   tmpVec3b));
        const startDot = math.dotVec3(plane.dir, math.subVec3(plane.pos, start, tmpVec3b));

        if ((startDot &gt; 0) &amp;&amp; (endDot &gt; 0)) {
            return false;
        } else if ((startDot &gt; 0) || (endDot &gt; 0)) {
            const denom = math.dotVec3(plane.dir, delta);
            if (Math.abs(denom) &gt;= 1e-6) {
                const ratio = math.dotVec3(plane.dir, tmpVec3b) / denom;
                if (startDot &gt; 0) {
                    s_min = Math.max(s_min, ratio);
                } else {
                    s_max = Math.min(s_max, ratio);
                }
            }
        }
    }

    const p0 = tmpVec4a;
    const p1 = tmpVec4b;
    toClipSpace(camera, (s_min &gt; 0) ? math.addVec3(start, math.mulVec3Scalar(delta, s_min, tmpVec3b), tmpVec3b) : start, p0);
    toClipSpace(camera, (s_max &lt; 1) ? math.addVec3(start, math.mulVec3Scalar(delta, s_max, tmpVec3b), tmpVec3b) : end,   p1);

    const p0Behind = ((p0[2] / p0[3]) &lt; -1) || (p0[3] &lt; 0);
    const p1Behind = ((p1[2] / p1[3]) &lt; -1) || (p1[3] &lt; 0);
    if (p0Behind &amp;&amp; p1Behind) {
        return false;
    }

    const t = (p0[3] + p0[2]) / ((p0[3] + p0[2]) - (p1[3] + p1[2]));

    if ((t &gt; 0) &amp;&amp; (t &lt; 1)) { //p0Behind || p1Behind) {
        // Find the intersection of a segment with the near plane in clip space, if it exists.&quot;&quot;&quot;
        // Calculate the interpolation factor t where the line segment crosses the near plane
        const delta = math.subVec4(p1, p0, tmpVec4c);
        math.mulVec4Scalar(delta, t, delta);
        math.addVec4(p0, delta, p0Behind ? p0 : p1);
    }

    // normalize clip space coords
    math.mulVec4Scalar(p0, 1.0 / p0[3]);
    math.mulVec4Scalar(p1, 1.0 / p1[3]);

    let t_min = 0.0;
    let t_max = 1.0;

    // If either point is outside the view frustum, clip the line segment

    for (let i = 0; i &lt; 2; ++i) {
        const denom = p1[i] - p0[i];

        const l = (-p0[3] - p0[i]) / denom;
        const r = ( p0[3] - p0[i]) / denom;

        if (denom &gt; 0) {
            t_min = Math.max(t_min, l);
            t_max = Math.min(t_max, r);
        } else {
            t_min = Math.max(t_min, r);
            t_max = Math.min(t_max, l);
        }
    }

    if (t_min &gt;= t_max) {
        return false;
    }

    // Calculate the clipped start and end points
    const ndcDelta = math.subVec4(p1, p0, tmpVec4c);
    math.addVec4(p0, math.mulVec4Scalar(ndcDelta, t_max, tmpVec4d), p1);
    math.addVec4(p0, math.mulVec4Scalar(ndcDelta, t_min, tmpVec4d), p0);

    math.mulVec4Scalar(p0, 1 / p0[3]);
    math.mulVec4Scalar(p1, 1 / p1[3]);

    toCanvasSpace(canvas, parentElement, p0, canvasStart);
    toCanvasSpace(canvas, parentElement, p1, canvasEnd);

    return true;
};

export class Dot3D extends Marker {
    constructor(scene, markerCfg, parentElement, cfg = {}) {
        const camera = scene.camera;

        super(scene, markerCfg);

        this.__visible = true;  // &quot;__&quot; to not interfere with Marker::_visible

        const handler = (cfgEvent, componentEvent) =&gt; {
            return event =&gt; {
                if (cfgEvent) {
                    cfgEvent(event);
                }
                this.fire(componentEvent, event, true);
            };
        };
        this._dot = new Dot(parentElement, {
            borderColor: cfg.borderColor,
            fillColor: cfg.fillColor,
            zIndex: cfg.zIndex,
            onMouseOver:   handler(cfg.onMouseOver,   &quot;mouseover&quot;),
            onMouseLeave:  handler(cfg.onMouseLeave,  &quot;mouseleave&quot;),
            onMouseWheel:  handler(cfg.onMouseWheel,  &quot;wheel&quot;),
            onMouseDown:   handler(cfg.onMouseDown,   &quot;mousedown&quot;),
            onMouseUp:     handler(cfg.onMouseUp,     &quot;mouseup&quot;),
            onMouseMove:   handler(cfg.onMouseMove,   &quot;mousemove&quot;),
            onTouchstart:  handler(cfg.onTouchstart,  &quot;touchstart&quot;),
            onTouchmove:   handler(cfg.onTouchmove,   &quot;touchmove&quot;),
            onTouchend:    handler(cfg.onTouchend,    &quot;touchend&quot;),
            onContextMenu: handler(cfg.onContextMenu, &quot;contextmenu&quot;)
        });

        const toClipSpace = (worldPos, p) =&gt; {
            // to homogeneous coords
            p.set(worldPos);
            p[3] = 1;

            // to clip space
            math.mulMat4v4(camera.viewMatrix, p, p);
            math.mulMat4v4(camera.projMatrix, p, p);
        };

        const toCanvasSpace = ndc =&gt; {
            const canvas = scene.canvas.canvas;
            ndc[0] = (1 + ndc[0]) * 0.5 * canvas.offsetWidth;
            ndc[1] = (1 - ndc[1]) * 0.5 * canvas.offsetHeight;
            transformToNode(canvas, parentElement, ndc);
        };

        const updateDotPos = () =&gt; {
            if (! this.__visible) {
                return;
            }
            const p0 = tmpVec4c;
            toClipSpace(this.worldPos, p0);
            math.mulVec3Scalar(p0, 1.0 / p0[3]);

            const outsideFrustum = ((p0[3] &lt; 0)
                                    ||
                                    (p0[0] &lt; -1) || (p0[0] &gt; 1)
                                    ||
                                    (p0[1] &lt; -1) || (p0[1] &gt; 1)
                                    ||
                                    (p0[2] &lt; -1) || (p0[2] &gt; 1));
            const culled = outsideFrustum || scene._sectionPlanesState.sectionPlanes.some(
                plane =&gt; (math.dotVec3(plane.dir, math.subVec3(plane.pos, this.worldPos, tmpVec3a)) &gt; 0));

            this._dot.setCulled(culled);
            if (!culled) {
                toCanvasSpace(p0);
                this._dot.setPos(p0[0], p0[1]);
            }
        };

        this.on(&quot;worldPos&quot;, updateDotPos);

        const onViewMatrix = camera.on(&quot;viewMatrix&quot;, updateDotPos);
        const onProjMatrix = camera.on(&quot;projMatrix&quot;, updateDotPos);
        const onCanvasBnd  = scene.canvas.on(&quot;boundary&quot;, updateDotPos);
        const planesUpdate = scene.on(&quot;sectionPlaneUpdated&quot;, updateDotPos);

        this._updatePosition = updateDotPos;

        this._cleanup = () =&gt; {
            camera.off(onViewMatrix);
            camera.off(onProjMatrix);
            scene.canvas.off(onCanvasBnd);
            scene.off(planesUpdate);
            this._dot.destroy();
        };
    }

    setClickable(value) {
        this._dot.setClickable(value);
    }

    setFillColor(value) {
        this._dot.setFillColor(value);
    }

    setBorderColor(value) {
        this._dot.setBorderColor(value);
    }

    setHighlighted(value) {
        this._dot.setHighlighted(value);
    }

    setOpacity(value) {
        this._dot.setOpacity(value);
    }

    setVisible(value) {
        if (this.__visible != value) {
            this.__visible = value;
            this._updatePosition();
            this._dot.setVisible(value);
        }
    }

    destroy() {
        this._cleanup();
        super.destroy();
    }

}

export class Label3D {
    constructor(scene, parentElement, cfg) {
        const camera = scene.camera;

        this._label = new Label(parentElement, cfg);
        this._start = math.vec3();
        this._mid   = math.vec3();
        this._end   = math.vec3();
        this._yOff  = 0;
        this.__visible = true;

        this._updatePos = () =&gt; {
            toClipSpace(camera, this._start, tmpVec4a);
            math.mulVec4Scalar(tmpVec4a, 1.0 / tmpVec4a[3]);
            toCanvasSpace(scene.canvas.canvas, parentElement, tmpVec4a, tmpVec2a);
            this._label.setPos(tmpVec2a[0], tmpVec2a[1]);
        };

        const setPosOnWire = (p0, p1, yOff) =&gt; {
            p0[0] += p1[0];
            p0[1] += p1[1];
            math.mulVec2Scalar(p0, .5);
            this._label.setPos(p0[0], p0[1] + yOff);
        };

        this._updatePosBetween = () =&gt; {
            const visibleA = clipSegment(scene, parentElement, this._start, this._mid, tmpVec2a, tmpVec2b);
            const visibleB = clipSegment(scene, parentElement, this._end,   this._mid, tmpVec2c, tmpVec2d);
            this._label.setCulled(! (visibleA || visibleB));
            if (visibleA &amp;&amp; visibleB) {
                tmpVec2b[0] += tmpVec2d[0];
                tmpVec2b[1] += tmpVec2d[1];
                math.mulVec2Scalar(tmpVec2b, .5);

                tmpVec2b[0] += tmpVec2a[0] + tmpVec2c[0];
                tmpVec2b[1] += tmpVec2a[1] + tmpVec2c[1];
                math.mulVec2Scalar(tmpVec2b, 1/3);
                this._label.setPos(tmpVec2b[0], tmpVec2b[1]);
            } else if (visibleA) {
                setPosOnWire(tmpVec2a, tmpVec2b, 0);
            } else if (visibleB) {
                setPosOnWire(tmpVec2c, tmpVec2d, 0);
            }
        };

        this._updatePosOnWire = () =&gt; {
            const visible = (clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b)
                             &amp;&amp;
                             (math.distVec2(tmpVec2a, tmpVec2b) &gt;= this._labelMinAxisLength));
            this._label.setCulled(!visible);
            if (visible) {
                setPosOnWire(tmpVec2a, tmpVec2b, this._yOff);
            }
        };

        let posUpdate = () =&gt; { };
        this._setUpdatePositions = (_posUpdate) =&gt; {
            posUpdate = _posUpdate;
            this._updatePositions();
        };
        this._updatePositions = () =&gt; {
            if (this.__visible) {
                posUpdate();
            }
        };

        const onViewMatrix = camera.on(&quot;viewMatrix&quot;, this._updatePositions);
        const onProjMatrix = camera.on(&quot;projMatrix&quot;, this._updatePositions);
        const onCanvasBnd  = scene.canvas.on(&quot;boundary&quot;, this._updatePositions);
        const planesUpdate = scene.on(&quot;sectionPlaneUpdated&quot;, this._updatePositions);

        this._cleanup = () =&gt; {
            camera.off(onViewMatrix);
            camera.off(onProjMatrix);
            scene.canvas.off(onCanvasBnd);
            scene.off(planesUpdate);
            this._label.destroy();
        };
    }

    setPos(p0) {
        this._start.set(p0);
        this._setUpdatePositions(this._updatePos);
    }

    setPosOnWire(p0, p1, yOff, labelMinAxisLength) {
        this._start.set(p0);
        this._end.set(p1);
        this._yOff = yOff;
        this._labelMinAxisLength = labelMinAxisLength;
        this._setUpdatePositions(this._updatePosOnWire);
    }

    setPosBetween(p0, p1, p2) {
        this._start.set(p0);
        this._mid.set(p1);
        this._end.set(p2);
        this._setUpdatePositions(this._updatePosBetween);
    }

    setFillColor(value) {
        this._label.setFillColor(value);
    }

    setHighlighted(value) {
        this._label.setHighlighted(value);
    }

    setText(value) {
        this._label.setText(value);
    }

    setClickable(value) {
        this._label.setClickable(value);
    }

    setVisible(value) {
        if (this.__visible != value) {
            this.__visible = value;
            this._updatePositions();
            this._label.setVisible(value);
        }
    }

    destroy() {
        this._cleanup();
    }

}

export class Wire3D {
    constructor(scene, parentElement, cfg) {
        const camera = scene.camera;

        this._wire  = new Wire(parentElement, cfg);
        this._start = math.vec3();
        this._end   = math.vec3();
        this.__visible = true;

        this._updatePositions = () =&gt; {
            if (! this.__visible) {
                return;
            }
            const visible = clipSegment(scene, parentElement, this._start, this._end, tmpVec2a, tmpVec2b);
            this._wire.setCulled(! visible);
            if (visible) {
                this._wire.setStartAndEnd(tmpVec2a[0], tmpVec2a[1], tmpVec2b[0], tmpVec2b[1]);
            }
        };

        const onViewMatrix = camera.on(&quot;viewMatrix&quot;, this._updatePositions);
        const onProjMatrix = camera.on(&quot;projMatrix&quot;, this._updatePositions);
        const onCanvasBnd  = scene.canvas.on(&quot;boundary&quot;, this._updatePositions);
        const planesUpdate = scene.on(&quot;sectionPlaneUpdated&quot;, this._updatePositions);

        this._cleanup = () =&gt; {
            camera.off(onViewMatrix);
            camera.off(onProjMatrix);
            scene.canvas.off(onCanvasBnd);
            scene.off(planesUpdate);
            this._wire.destroy();
        };
    }

    setEnds(start, end) {
        this._start.set(start);
        this._end.set(end);
        this._updatePositions();
    }

    setClickable(value) {
        this._wire.setClickable(value);
    }

    setColor(value) {
        this._wire.setColor(value);
    }

    setHighlighted(value) {
        this._wire.setHighlighted(value);
    }

    setOpacity(value) {
        this._wire.setOpacity(value);
    }

    setVisible(value) {
        if (this.__visible != value) {
            this.__visible = value;
            this._updatePositions();
            this._wire.setVisible(value);
        }
    }

    destroy() {
        this._cleanup();
    }

}

export const marker3D = function(scene, color) {
    const marker = new Dot3D(scene, {}, scene.canvas.canvas.parentNode, {
        borderColor: &quot;white&quot;,
        fillColor: color,
        zIndex: 100
    });

    return {
        update: function(worldPos) {
            if (worldPos)
            {
                marker.worldPos = worldPos;
            }
            marker.setVisible(!!worldPos);
        },

        setFillColor:  c =&gt; marker.setFillColor(c),
        setHighlighted: h =&gt; marker.setHighlighted(h),
        getCanvasPos:  () =&gt; marker.canvasPos,
        getWorldPos:   () =&gt; marker.worldPos,
        destroy:       () =&gt; marker.destroy()
    };
};

export const wire3D = function(scene, color) {
    const wire = new Wire3D(scene, scene.canvas.canvas.ownerDocument.body, {
        color: color,
        thickness: 1,
        thicknessClickable: 6   // TODO: Remove to make not clickable?
    });
    wire.setVisible(false);
    return {
        update: (startWorldPos, endWorldPos) =&gt; {
            if (endWorldPos)
            {
                wire.setEnds(startWorldPos, endWorldPos);
            }
            wire.setVisible(!!endWorldPos);
        },

        setColor: c =&gt; wire.setColor(c),
        destroy: () =&gt; wire.destroy()
    };
};

export function activateDraggableDot(dot, cfg) {
    const extractCFG = function(propName, defaultValue) {
        if (propName in cfg) {
            return cfg[propName];
        } else if (defaultValue !== undefined) {
            return defaultValue;
        } else {
            throw &quot;config missing: &quot; + propName;
        }
    };

    const viewer = extractCFG(&quot;viewer&quot;);
    const ray2WorldPos = extractCFG(&quot;ray2WorldPos&quot;);
    const handleMouseEvents = extractCFG(&quot;handleMouseEvents&quot;, false);
    const handleTouchEvents = extractCFG(&quot;handleTouchEvents&quot;, false);
    const onStart = extractCFG(&quot;onStart&quot;, nop);
    const onMove  = extractCFG(&quot;onMove&quot;,  nop);
    const onEnd   = extractCFG(&quot;onEnd&quot;,   nop);

    const scene = viewer.scene;
    const canvas = scene.canvas.canvas;

    const pickWorldPos = canvasPos =&gt; {
        const origin = math.vec3();
        const direction = math.vec3();
        math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
        return ray2WorldPos(origin, direction, canvasPos);
    };

    const onChange = event =&gt; {
        const canvasPos = math.vec2([ event.clientX, event.clientY ]);
        transformToNode(canvas.ownerDocument.documentElement, canvas, canvasPos);
        onMove(canvasPos, pickWorldPos(canvasPos));
    };

    let currentDrag = null;

    const onDragMove = function(event) {
        const e = currentDrag.matchesEvent(event);
        if (e)
        {
            onChange(e);
        }
    };

    const onDragEnd = function(event) {
        const e = currentDrag.matchesEvent(event);
        if (e)
        {
            dot.setOpacity(idleOpacity);
            currentDrag.cleanup();
            onChange(e);
            onEnd();
        }
    };

    const startDrag = function(matchesEvent, cleanupHandlers) {
        if (currentDrag) {
            currentDrag.cleanup();
        }

        dot.setOpacity(1.0);
        dot.setClickable(false);
        viewer.cameraControl.active = false;

        currentDrag = {
            matchesEvent: matchesEvent,
            cleanup: function() {
                currentDrag = null;
                dot.setClickable(true);
                viewer.cameraControl.active = true;
                cleanupHandlers();
            }
        };

        onStart();
    };

    const cleanupDotHandlers = [ ];
    const dot_on = function(event, callback) {
        const id = dot.on(event, callback);
        cleanupDotHandlers.push(() =&gt; dot.off(id));
    };

    if (handleMouseEvents)
    {
        dot_on(&quot;mouseover&quot;,  () =&gt; (! currentDrag) &amp;&amp; dot.setOpacity(1.0));
        dot_on(&quot;mouseleave&quot;, () =&gt; (! currentDrag) &amp;&amp; dot.setOpacity(idleOpacity));
        dot_on(&quot;mousedown&quot;,  event =&gt; {
            if (event.which === 1)
            {
                canvas.addEventListener(&quot;mousemove&quot;, onDragMove);
                canvas.addEventListener(&quot;mouseup&quot;,   onDragEnd);
                startDrag(
                    event =&gt; (event.which === 1) &amp;&amp; event,
                    () =&gt; {
                        canvas.removeEventListener(&quot;mousemove&quot;, onDragMove);
                        canvas.removeEventListener(&quot;mouseup&quot;,   onDragEnd);
                    });
            }
        });
    }

    if (handleTouchEvents)
    {
        let touchStartId;
        dot_on(&quot;touchstart&quot;, event =&gt; {
            event.preventDefault();
            if (event.touches.length === 1)
            {
                touchStartId = event.touches[0].identifier;
                startDrag(
                    event =&gt; [...event.changedTouches].find(e =&gt; e.identifier === touchStartId),
                    () =&gt; { touchStartId = null; });
            }
        });
        dot_on(&quot;touchmove&quot;, event =&gt; {
            event.preventDefault();
            onDragMove(event);
        });
        dot_on(&quot;touchend&quot;,  event =&gt; {
            event.preventDefault();
            onDragEnd(event);
        });
    }

    const idleOpacity = 0.8;
    dot.setOpacity(idleOpacity);

    return function() {
        currentDrag &amp;&amp; currentDrag.cleanup();
        cleanupDotHandlers.forEach(c =&gt; c());
        dot.setOpacity(1.0);
    };
};

export function activateDraggableDots(cfg) {
    const extractCFG = function(propName, defaultValue) {
        if (propName in cfg) {
            return cfg[propName];
        } else if (defaultValue !== undefined) {
            return defaultValue;
        } else {
            throw &quot;config missing: &quot; + propName;
        }
    };

    const viewer = extractCFG(&quot;viewer&quot;);
    const handleMouseEvents = extractCFG(&quot;handleMouseEvents&quot;, false);
    const handleTouchEvents = extractCFG(&quot;handleTouchEvents&quot;, false);
    const pointerLens = extractCFG(&quot;pointerLens&quot;, null);
    const dots = extractCFG(&quot;dots&quot;);
    const ray2WorldPos = extractCFG(&quot;ray2WorldPos&quot;);
    const onEnd = extractCFG(&quot;onEnd&quot;, nop);

    const updatePointerLens = (pointerLens
                               ? function(canvasPos) {
                                   pointerLens.visible = !! canvasPos;
                                   if (canvasPos)
                                   {
                                       pointerLens.canvasPos = canvasPos;
                                   }
                               }
                               : () =&gt; { });

    const cleanups = dots.map(dot =&gt; {
        let initPos;
        return activateDraggableDot(dot, {
            handleMouseEvents: handleMouseEvents,
            handleTouchEvents: handleTouchEvents,
            viewer: viewer,
            ray2WorldPos: (orig, dir, canvasPos) =&gt; (ray2WorldPos(orig, dir, canvasPos) || initPos),
            onStart: () =&gt; {
                initPos = dot.worldPos.slice();
                setOtherDotsActive(false, dot);
            },
            onMove: (canvasPos, worldPos) =&gt; {
                updatePointerLens(canvasPos);
                dot.worldPos = worldPos;
            },
            onEnd: () =&gt; {
                if (! onEnd(initPos, dot)) {
                    dot.worldPos = initPos;
                }
                updatePointerLens(null);
                setOtherDotsActive(true, dot);
            }
        });
    });

    const setOtherDotsActive = (active, dot) =&gt; dots.forEach(d =&gt; (d !== dot) &amp;&amp; d.setClickable(active));
    setOtherDotsActive(true);

    return function() {
        cleanups.forEach(c =&gt; c());
        updatePointerLens(null);
    };
}

export const touchPointSelector = function(viewer, pointerCircle, ray2WorldPos) {
    return function(onCancel, onChange, onCommit) {
        const scene = viewer.scene;
        const canvas = scene.canvas.canvas;
        const longTouchTimeoutMs = 300;
        const moveTolerance = 20;

        const copyCanvasPos = (event, vec2) =&gt; {
            vec2[0] = event.clientX;
            vec2[1] = event.clientY;
            transformToNode(canvas.ownerDocument.documentElement, canvas, vec2);
            return vec2;
        };

        const pickWorldPos = canvasPos =&gt; {
            const origin = math.vec3();
            const direction = math.vec3();
            math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, origin, direction);
            return ray2WorldPos(origin, direction);
        };

        let longTouchTimeout = null;
        const nop = () =&gt; { };
        let onSingleTouchMove = nop;
        let startTouchIdentifier;

        const resetAction = function() {
            pointerCircle.stop();
            clearTimeout(longTouchTimeout);
            viewer.cameraControl.active = true;
            onSingleTouchMove = nop;
            startTouchIdentifier = null;
        };

        const cleanup = function() {
            resetAction();
            canvas.removeEventListener(&quot;touchstart&quot;, onCanvasTouchStart);
            canvas.removeEventListener(&quot;touchmove&quot;,  onCanvasTouchMove);
            canvas.removeEventListener(&quot;touchend&quot;,   onCanvasTouchEnd);
        };

        const onCanvasTouchStart = function(event) {
            const touches = event.touches;

            if (touches.length !== 1)
            {
                resetAction();
                onCancel();
            }
            else
            {
                const startTouch = touches[0];
                const startCanvasPos = copyCanvasPos(startTouch, math.vec2());

                const startWorldPos = pickWorldPos(startCanvasPos);
                if (startWorldPos)
                {
                    startTouchIdentifier = startTouch.identifier;

                    onSingleTouchMove = canvasPos =&gt; {
                        if (math.distVec2(startCanvasPos, canvasPos) &gt; moveTolerance)
                        {
                            resetAction();
                        }
                    };

                    longTouchTimeout = setTimeout(
                        function() {
                            pointerCircle.start(startCanvasPos);

                            longTouchTimeout = setTimeout(
                                function() {
                                    pointerCircle.stop();

                                    viewer.cameraControl.active = false;

                                    onSingleTouchMove = canvasPos =&gt; {
                                        onChange(canvasPos, pickWorldPos(canvasPos));
                                    };

                                    onSingleTouchMove(startCanvasPos);
                                },
                                longTouchTimeoutMs);
                        },
                        250);
                }
            }
        };
        canvas.addEventListener(&quot;touchstart&quot;, onCanvasTouchStart, {passive: true});

        // canvas.addEventListener(&quot;touchcancel&quot;, e =&gt; console.log(&quot;touchcancel&quot;, e), {passive: true});

        const onCanvasTouchMove = function(event) {
            const touch = [...event.changedTouches].find(e =&gt; e.identifier === startTouchIdentifier);
            if (touch)
            {
                onSingleTouchMove(copyCanvasPos(touch, math.vec2()));
            }
        };
        canvas.addEventListener(&quot;touchmove&quot;, onCanvasTouchMove, {passive: true});

        const onCanvasTouchEnd = function(event) {
            const touch = [...event.changedTouches].find(e =&gt; e.identifier === startTouchIdentifier);
            if (touch)
            {
                cleanup();
                const canvasPos = copyCanvasPos(touch, math.vec2());
                onCommit(canvasPos, pickWorldPos(canvasPos));
            }
        };
        canvas.addEventListener(&quot;touchend&quot;, onCanvasTouchEnd, {passive: true});

        return cleanup;
    };
};

export const triangulateEarClipping = function(planeCoords) {
    const polygonVertices = [ ];
    for (let i = 0; i &lt; planeCoords.length; ++i)
        polygonVertices.push(i);

    const isCCW = (function() {
        const ba = math.vec2();
        const bc = math.vec2();

        let anglesSum = 0;
        const angles = [ ];

        for (let i = 0; i &lt; polygonVertices.length; ++i)
        {
            const a = planeCoords[polygonVertices[i]];
            const b = planeCoords[polygonVertices[(i + 1) % polygonVertices.length]];
            const c = planeCoords[polygonVertices[(i + 2) % polygonVertices.length]];

            math.subVec2(a, b, ba);
            math.subVec2(c, b, bc);

            const theta = math.dotVec2(ba, bc) / Math.sqrt(math.sqLenVec2(ba) * math.sqLenVec2(bc));
            const angle = Math.acos(Math.max(-1, Math.min(theta, 1)));
            const convex = (ba[0] * bc[1] - ba[1] * bc[0]) &gt;= 0;
            anglesSum += convex ? angle : (2 * Math.PI - angle);
        }

        return anglesSum &lt; (polygonVertices.length * Math.PI);
    })();

    const pointInTriangle = (function() {
        const sign = (p1, p2, p3) =&gt; {
            return (p1[0] - p3[0]) * (p2[1] - p3[1]) - (p2[0] - p3[0]) * (p1[1] - p3[1]);
        };

        return (pt, v1, v2, v3) =&gt; {
            const d1 = sign(pt, v1, v2);
            const d2 = sign(pt, v2, v3);
            const d3 = sign(pt, v3, v1);

            const has_neg = (d1 &lt; 0) || (d2 &lt; 0) || (d3 &lt; 0);
            const has_pos = (d1 &gt; 0) || (d2 &gt; 0) || (d3 &gt; 0);

            return !(has_neg &amp;&amp; has_pos);
        };
    })();

    const baseTriangles = [ ];

    const vertices = (isCCW ? polygonVertices : polygonVertices.slice(0).reverse()).map(i =&gt; ({ idx: i }));
    vertices.forEach((v, i) =&gt; {
        v.prev = vertices[(i - 1 + vertices.length) % vertices.length];
        v.next = vertices[(i + 1)                   % vertices.length];
    });

    const ba = math.vec2();
    const bc = math.vec2();

    while (vertices.length &gt; 2) {
        let earIdx = 0;
        while (true) {
            if (earIdx &gt;= vertices.length)
            {
                throw `isCCW = ${isCCW}; earIdx = ${earIdx}; len = ${vertices.length}`;
            }
            const v = vertices[earIdx];

            const a = planeCoords[v.prev.idx];
            const b = planeCoords[v.idx];
            const c = planeCoords[v.next.idx];

            math.subVec2(a, b, ba);
            math.subVec2(c, b, bc);

            if (((ba[0] * bc[1] - ba[1] * bc[0]) &gt;= 0) // a convex vertex
                &amp;&amp;
                vertices.every( // no other vertices inside
                    vv =&gt; ((vv === v)
                           ||
                           (vv === v.prev)
                           ||
                           (vv === v.next)
                           ||
                           !pointInTriangle(planeCoords[vv.idx], a, b, c))))
                break;
            ++earIdx;
        }

        const ear = vertices[earIdx];
        vertices.splice(earIdx, 1);

        baseTriangles.push([ ear.idx, ear.next.idx, ear.prev.idx ]);

        const prev = ear.prev;
        prev.next = ear.next;
        const next = ear.next;
        next.prev = ear.prev;
    }

    return [ planeCoords, baseTriangles, isCCW ];
};

export const addMousePressListener = function(element, onChange) {
    const moveTolerance = 4;

    const copyElementPos = (event, out) =&gt; {
        out[0] = event.clientX;
        out[1] = event.clientY;
        transformToNode(element.ownerDocument.documentElement, element, out);
        return out;
    };

    let buttonDown = false;

    const cleanups = [ ];
    const cleanup = () =&gt; cleanups.forEach(c =&gt; c());

    const addElementEventListener = (type, listener) =&gt; {
        element.addEventListener(type, listener);
        cleanups.push(() =&gt; element.removeEventListener(type, listener));
    };

    const downPos = math.vec2();
    addElementEventListener(&quot;mousedown&quot;, function(event) {
        if (event.which === 1) {
            buttonDown = true;
            onChange(copyElementPos(event, downPos));
        }
    });

    addElementEventListener(&quot;mousemove&quot;, function(event) {
        copyElementPos(event, tmpVec2a);
        if (buttonDown &amp;&amp; (math.distVec2(downPos, tmpVec2a) &gt; moveTolerance)) {
            buttonDown = false;
        }
        if (buttonDown || (! event.buttons &amp; 1)) {
            onChange(tmpVec2a);
        }
    });

    addElementEventListener(&quot;mouseup&quot;, function(event) {
        if ((event.which === 1) &amp;&amp; buttonDown) {
            const commit = onChange(copyElementPos(event, tmpVec2a));
            if (commit) {
                cleanup();
                commit();
            }
        }
    });

    return cleanup;
};

export const addTouchPressListener = function(element, cameraControl, pointerCircle, onChange) {
    const longTouchTimeoutMs = 300;
    const moveTolerance = 20;
    const startPos = math.vec2();

    const copyElementPos = (event, out) =&gt; {
        out[0] = event.clientX;
        out[1] = event.clientY;
        transformToNode(element.ownerDocument.documentElement, element, out);
        return out;
    };

    let longTouchTimeout = null;
    let onSingleTouchMove = nop;
    let startTouchIdentifier;

    const resetAction = function() {
        clearTimeout(longTouchTimeout);
        pointerCircle.stop();
        cameraControl.active = true;
        onSingleTouchMove = nop;
        startTouchIdentifier = null;
    };

    const cleanups = [ ];
    const cleanup = () =&gt; cleanups.forEach(c =&gt; c());

    const addElementEventListener = (type, listener) =&gt; {
        element.addEventListener(type, listener, {passive: true});
        cleanups.push(() =&gt; element.removeEventListener(type, listener));
    };

    addElementEventListener(&quot;touchstart&quot;, function(event) {
        const touches = event.touches;

        if (touches.length !== 1)
        {
            resetAction();
            onChange(null);
        }
        else
        {
            const touch = touches[0];
            copyElementPos(touch, startPos);

            startTouchIdentifier = touch.identifier;

            onSingleTouchMove = elementPos =&gt; {
                if (math.distVec2(startPos, elementPos) &gt; moveTolerance)
                {
                    resetAction();
                }
            };

            longTouchTimeout = setTimeout(
                function() {
                    pointerCircle.start(startPos);

                    longTouchTimeout = setTimeout(
                        function() {
                            pointerCircle.stop();
                            cameraControl.active = false;
                            onSingleTouchMove = onChange;
                            onSingleTouchMove(startPos);
                        },
                        longTouchTimeoutMs);
                },
                250);
        }
    });

    // element.addEventListener(&quot;touchcancel&quot;, e =&gt; console.log(&quot;touchcancel&quot;, e), {passive: true});

    addElementEventListener(&quot;touchmove&quot;, function(event) {
        const touch = [...event.changedTouches].find(e =&gt; e.identifier === startTouchIdentifier);
        if (touch)
        {
            onSingleTouchMove(copyElementPos(touch, tmpVec2a));
        }
    });

    addElementEventListener(&quot;touchend&quot;, function(event) {
        const touch = [...event.changedTouches].find(e =&gt; e.identifier === startTouchIdentifier);
        if (touch)
        {
            const commit = onChange(copyElementPos(touch, tmpVec2a));
            resetAction();
	    if (commit) {
	        cleanup();
		commit();
	    } else {
                onChange(null);
            }
        }
    });

    return () =&gt; {
        resetAction();
        cleanup();
    };
};

export const startPolygonCreate = function(scene, pointerLens, addPressListener, pickRayResult, onChange, onConclude) {
    const canvas = scene.canvas.canvas;

    const updatePointerLens = (pointerLens
                               ? function(canvasPos, isSnapped) {
                                   pointerLens.visible = !! canvasPos;
                                   if (canvasPos)
                                   {
                                       pointerLens.canvasPos = canvasPos;
                                       pointerLens.snapped = !! isSnapped;
                                   }
                               }
                               : () =&gt; { });

    const testLastSegmentIntersects = (function() {
        const onSegment = (p, q, r) =&gt; ((q[0] &lt;= Math.max(p[0], r[0])) &amp;&amp;
                                        (q[0] &gt;= Math.min(p[0], r[0])) &amp;&amp;
                                        (q[1] &lt;= Math.max(p[1], r[1])) &amp;&amp;
                                        (q[1] &gt;= Math.min(p[1], r[1])));

        const orient = (p, q, r) =&gt; {
            const val = (q[1] - p[1]) * (r[0] - q[0]) - (q[0] - p[0]) * (r[1] - q[1]);
            // collinear
            // clockwise
            // counterclockwise
            return ((val === 0) ? 0 : ((val &gt; 0) ? 1 : 2));
        };

        return function(pos2D, lastSegmentClosesLoop) {
            const s = lastSegmentClosesLoop ? 1 : 0;
            const a = pos2D[(pos2D.length - 2 + s) % pos2D.length];
            const b = pos2D[(pos2D.length - 1 + s) % pos2D.length];

            for (let i = s; i &lt; pos2D.length - 2 - 1 + s; ++i) {
                const c = pos2D[i];
                const d = pos2D[i + 1];

                const o1 = orient(a, b, c);
                const o2 = orient(a, b, d);
                const o3 = orient(c, d, a);
                const o4 = orient(c, d, b);

                if (((o1 !== o2) &amp;&amp; (o3 !== o4))       || // General case
                    ((o1 === 0) &amp;&amp; onSegment(a, c, b)) || // a, b and c are collinear and c lies on segment ab
                    ((o2 === 0) &amp;&amp; onSegment(a, d, b)) || // a, b and d are collinear and d lies on segment ab
                    ((o3 === 0) &amp;&amp; onSegment(c, a, d)) || // c, d and a are collinear and a lies on segment cd
                    ((o4 === 0) &amp;&amp; onSegment(c, b, d)))   // c, d and b are collinear and b lies on segment cd
                {
                    return true;
                }
            }

            return false;
        };
    })();

    const getPlane = (points) =&gt; (points.length &gt;= 3) &amp;&amp; (function() {
        const u      = math.normalizeVec3(math.subVec3(points[1], points[0], math.vec3()));
        const v20    = math.normalizeVec3(math.subVec3(points[2], points[0], tmpVec3a));
        const normal = math.normalizeVec3(math.cross3Vec3(u, v20, math.vec3()));
        const v      = math.normalizeVec3(math.cross3Vec3(normal, u, math.vec3()));
        return {
            normal: normal,
            origin: math.vec3(points[0]),
            u:      u,
            v:      v
        };
    })();

    const vertices = [ ];
    let currentInteraction;

    (function selectNextPoint() {
        const plane = getPlane(vertices);

        const canvasPos2Ray = (canvasPos, dst) =&gt; (math.canvasPosToWorldRay(canvas, scene.camera.viewMatrix, scene.camera.projMatrix, scene.camera.projection, canvasPos, dst.origin, dst.direction), dst);

        const pickRay = (ray) =&gt; {
            const pickResult = pickRayResult(ray);
            const snapWorldPos = pickResult &amp;&amp; pickResult.entity &amp;&amp; ((! plane) || pickResult.snapped) &amp;&amp; pickResult.worldPos;
            if (plane) {
                const originDistance = math.dotVec3(plane.normal, plane.origin);
                const snapPlaneDist = (snapWorldPos
                                       ? ((originDistance - math.dotVec3(snapWorldPos, plane.normal)))
                                       : window.Infinity);
                if (Math.abs(snapPlaneDist) &lt; 0.0001) {
                    const ret = math.vec3();
                    return {
                        worldPos: math.addVec3(snapWorldPos, math.mulVec3Scalar(plane.normal, snapPlaneDist, ret), ret),
                        snapped:  true
                    };
                } else {
                    return {
                        worldPos: planeIntersect(originDistance, plane.normal, ray.origin, ray.direction),
                        snapped:  false
                    };
                }
            } else {
                return {
                    worldPos: snapWorldPos,
                    snapped:  pickResult &amp;&amp; pickResult.snapped
                };
            }
        };

        let placeVertex = false;
        const removePressListener = addPressListener(
            (inputCanvasPos) =&gt; {
                const rayPick = inputCanvasPos &amp;&amp; pickRay(canvasPos2Ray(inputCanvasPos, tmpRay));
                const worldPos = rayPick &amp;&amp; rayPick.worldPos;
                return onWorldPos(worldPos, inputCanvasPos, rayPick &amp;&amp; rayPick.snapped);
            });

        const onWorldPos = (worldPos, inputCanvasPos, rayPickSnapped) =&gt; {
                const canvasPos = worldPos ? scene.camera.projectWorldPos(worldPos) : inputCanvasPos;
                const firstMarker = (vertices.length &gt; 0) &amp;&amp; (function() {
                    const v = vertices[0];
                    return {
                        canvasPos: scene.camera.projectWorldPos(v),
                        worldPos: v
                    };
                })();
                const snapToFirst = (vertices.length &gt;= 3) &amp;&amp; ((canvasPos &amp;&amp; (math.distVec2(canvasPos, firstMarker.canvasPos) &lt; 10))
                                                               ||
                                                               (worldPos &amp;&amp; math.compareVec3(worldPos, firstMarker.worldPos)));

                updatePointerLens(snapToFirst ? firstMarker.canvasPos : canvasPos, snapToFirst || rayPickSnapped);

                const lastPointOverlaps = (inputCanvasPos
                                           &amp;&amp;
                                           ((! worldPos)
                                            ||
                                            ((vertices.length &lt; 3)
                                             ? vertices.some(v =&gt; math.compareVec3(v, worldPos))
                                             : math.compareVec3(vertices[vertices.length - 1], worldPos))));

                const points = vertices.concat(((! snapToFirst) &amp;&amp; worldPos &amp;&amp; (! lastPointOverlaps)) ? [worldPos] : []);

                const curPlane = (! lastPointOverlaps) &amp;&amp; (plane || getPlane(points));

                const uvs = curPlane &amp;&amp; points.map(p =&gt; {
                    math.subVec3(p, curPlane.origin, tmpVec3a);
                    return math.vec2([ math.dotVec3(tmpVec3a, curPlane.u), math.dotVec3(tmpVec3a, curPlane.v) ]);
                });

                const isValid = (! lastPointOverlaps) &amp;&amp; (! (uvs &amp;&amp; testLastSegmentIntersects(uvs, snapToFirst)));
                const geometry = isValid &amp;&amp; uvs &amp;&amp; (snapToFirst || (! testLastSegmentIntersects(uvs, true))) &amp;&amp; (function() {
                    try {
                        const [ baseVertices, baseTriangles, isCCW ] = triangulateEarClipping(uvs);
                        return {
                            faces: baseTriangles,
                            vertices: baseVertices.map(uv =&gt; math.addVec3(
                                curPlane.origin,
                                math.addVec3(
                                    math.mulVec3Scalar(curPlane.u, uv[0], tmpVec3a),
                                    math.mulVec3Scalar(curPlane.v, uv[1], tmpVec3b),
                                    tmpVec3a),
                                math.vec3()))
                        };
                    } catch (e) {
                        console.warn(&quot;e&quot;, e);
                        return false;
                    }
                })();

                onChange(points, snapToFirst, isValid, geometry);

                return placeVertex = (isValid &amp;&amp; (snapToFirst
                                                  ? () =&gt; {
                                                      updatePointerLens(null);
                                                      onConclude();
                                                  }
                                                  : () =&gt; {
                                                      vertices.push(math.vec3(worldPos));
                                                      updatePointerLens(null);
                                                      selectNextPoint();
                                                  }));
            };

        currentInteraction = {
            closePolygon: (() =&gt; {
                const commit = (vertices.length &gt;= 3) &amp;&amp; onWorldPos(vertices[0]);
                if (commit) {
                    removePressListener();
                    commit();
                }
                return !! commit;
            }),
            placeVertex: () =&gt; {
                if (placeVertex) {
                    removePressListener();
                    placeVertex();
                }
                return !!placeVertex;
            },
            popVertex: () =&gt; {
                if (vertices.length &gt; 0) {
                    removePressListener();
                    vertices.pop();
                    selectNextPoint();
                    return true;
                } else {
                    return false;
                }
            },
            removePressListener: removePressListener,
            updateOnChange: () =&gt; onWorldPos()
        };
    })();

    return {
        cancel: () =&gt; {
            currentInteraction.removePressListener();
            updatePointerLens(null);
        },
        closePolygon:   () =&gt; currentInteraction.closePolygon(),
        placeVertex:    () =&gt; currentInteraction.placeVertex(),
        popVertex:      () =&gt; currentInteraction.popVertex(),
        updateOnChange: () =&gt; currentInteraction.updateOnChange()
    };
};
</code></pre>

</div>

<footer class="footer">
  Generated by <a href="https://esdoc.org">ESDoc<span data-ice="esdocVersion">(1.1.0)</span><img src="./image/esdoc-logo-mini-black.png"></a>
</footer>

<script src="script/search_index.js"></script>
<script src="script/search.js"></script>
<script src="script/pretty-print.js"></script>
<script src="script/inherited-summary.js"></script>
<script src="script/test-summary.js"></script>
<script src="script/inner-link.js"></script>
<script src="script/patch-for-local.js"></script>
</body>
</html>
